// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

// ************************************************************************* //
//                            avtMFEMFileFormat.h                            //
// ************************************************************************* //

#ifndef AVT_MFEM_FILE_FORMAT_H
#define AVT_MFEM_FILE_FORMAT_H

#include <avtSTMDFileFormat.h>
#include <avtDataSelection.h>

#include <map>
#include <string>
#include <utility>
#include <vector>

#include "mfem.hpp"
class JSONRoot;
class DBOptionsAttributes;

// ****************************************************************************
//  Class: avtMFEMFileFormat
//
//  Purpose:
//       MFEM database reader with LOD / refinement controls.
//
//  Programmer: harrison37 -- generated by xml2avt
//  Creation:   Fri May 23 15:16:20 PST 2014
//
//  Modifications:
//   Cyrus Harrison, Wed Sep 24 10:47:00 PDT 2014
//   Enable time varying metadata and SIL.
//
//   Mark C. Miller, Mon Dec 11 15:50:16 PST 2017
//   Add support for an mfem_cat file
// 
//   Justin Privitera, Wed Aug 24 11:08:51 PDT 2022
//   Removed `GetRefinedMesh`, `GetRefinedElementColoring`, and
//   `GetRefinedElementAttribute`. These methods can be found in the avtMFEM
//   lib.
// 
//    Justin Privitera, Wed Aug 24 11:08:51 PDT 2022
//    Added `m_new_refine`, a boolean to toggle between using new MFEM LOR or 
//    legacy MFEM LOR. When true, the new scheme is enabled. It is never set to
//    true yet, but will be in the future.
// 
//    Justin Privitera, Tue Oct 18 09:53:50 PDT 2022
//    Added DBOptionsAttributes forward declaration and as an argument to
//    avtMFEMFileFormat.
// ****************************************************************************

class avtMFEMFileFormat : public avtSTMDFileFormat
{
  public:
                       avtMFEMFileFormat(const char *, 
                                         const DBOptionsAttributes *);
    virtual           ~avtMFEMFileFormat();
    
    // VisIt can't cache for us b/c we need to implement LOD support. 
    virtual bool           CanCacheVariable(const char *var) {return false;}
    // Used to enable support for avtResolutionSelection
    virtual void        RegisterDataSelections(
                            const std::vector<avtDataSelection_p> &selList,
                            std::vector<bool> *selectionsApplied);


    virtual const char    *GetType(void)   { return "MFEM"; };
    virtual void           FreeUpResources(void); 

    virtual vtkDataSet    *GetMesh(int, const char *);
    virtual vtkDataArray  *GetVar(int, const char *);
    virtual vtkDataArray  *GetVectorVar(int, const char *);

    virtual int            GetCycle();
    virtual double         GetTime();

    virtual void           ActivateTimestep(void);
  protected:

    virtual void           PopulateDatabaseMetaData(avtDatabaseMetaData *);
    bool                   HasInvariantMetaData(void) const { return false; };
    bool                   HasInvariantSIL(void) const      { return false; };
  
  private:
    int                              selectedLOD;

    mfem::Mesh                     *FetchMesh(const std::string &mesh_name,
                                              int chunk);
                                                                                                  
    vtkDataArray                    *GetRefinedVar(const std::string &mesh_name,
                                                   int chunk,
                                                   int lod);
                                                   
    JSONRoot                        *root;  

    // For handling .mfem_cat files
    void                             BuildCatFileMap(const std::string &cat_path);
    void                             FetchDataFromCatFile(const std::string &cat_path,
                                                          const std::string &mesh_path,
                                                          std::istringstream &imeshstr);
    std::map<std::string, std::pair<size_t,size_t> > catFileMap;

    bool                            m_new_refine;
};

#endif
